package site.lianwu.mybatis.plus.query.sample;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
import site.lianwu.mybatis.plus.query.NestedQuery;
import site.lianwu.mybatis.plus.query.Query;
import site.lianwu.mybatis.plus.query.QueryWrappers;
import site.lianwu.mybatis.plus.query.define.ConditionType;
import site.lianwu.mybatis.plus.query.processor.GeneralQueryClassProcessor;
import site.lianwu.mybatis.plus.query.processor.GeneralQueryWrapperProcessor;
import site.lianwu.mybatis.plus.query.sample.model.entity.User;

import java.time.LocalDate;
import java.util.concurrent.TimeUnit;


public class JmhTests {

    @BenchmarkMode(Mode.AverageTime)
    @State(Scope.Thread)
    @Warmup(iterations = 5, time = 1)
    @Fork(1)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    @Measurement(iterations = 5)
    public static class ManualSettingQueryWrapper {

        static UserDTO dto;

        @Setup
        public void setUp() {
            UserDTO2 userDto2 = new UserDTO2();
            userDto2.setName("Jack");
            userDto2.setAge(24);
            dto = UserDTO.builder()
                    .id(2L)
                    .email(".com")
                    .birthday(LocalDate.of(2000, 1, 1))
                    .userDto2(userDto2)
                    .build();
        }

        @Benchmark
        public void manualSetting(Blackhole blackhole)  {
            blackhole.consume(condition(dto));
        }

        private QueryWrapper<User> condition(UserDTO dto) {
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq(dto.getId() != null, "id", dto.getId())
                    .likeLeft(StringUtils.isNotBlank(dto.getEmail()), "email", dto.getEmail())
                    .ge(dto.getBirthday() != null, "birthday", dto.getBirthday());
            UserDTO2 userDto2 = dto.getUserDto2();
            if (userDto2 != null) {
                queryWrapper.like(StringUtils.isNotBlank(userDto2.getName()), "name", userDto2.getName())
                        .le(userDto2.getAge() != null, "age", userDto2.getAge());
            }
            return queryWrapper;
        }

    }

    @BenchmarkMode(Mode.AverageTime)
    @State(Scope.Thread)
    @Warmup(iterations = 5, time = 1)
    @Fork(1)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    @Measurement(iterations = 5)
    public static class WithCachedSecureQueryClassProcessor {

        static UserDTO dto;

        @Setup
        public void setUp() {
            UserDTO2 userDto2 = new UserDTO2();
            userDto2.setName("Jack");
            userDto2.setAge(24);
            dto = UserDTO.builder()
                    .id(2L)
                    .email(".com")
                    .birthday(LocalDate.of(2000, 1, 1))
                    .userDto2(userDto2)
                    .build();
        }

        @Benchmark
        public void withCachedSecureQueryClassProcessor(Blackhole blackhole) {
            blackhole.consume(QueryWrappers.parse(dto));
        }

    }

    @BenchmarkMode(Mode.AverageTime)
    @State(Scope.Thread)
    @Warmup(iterations = 5, time = 1)
    @Fork(1)
    @OutputTimeUnit(TimeUnit.MICROSECONDS)
    @Measurement(iterations = 5)
    public static class WithGeneralQueryClassProcessor {

        static UserDTO dto;

        @Setup
        public void setUp() {
            QueryWrappers.initQueryWrapperProcessor(new GeneralQueryWrapperProcessor(new GeneralQueryClassProcessor()));
            UserDTO2 userDto2 = new UserDTO2();
            userDto2.setName("Jack");
            userDto2.setAge(24);
            dto = UserDTO.builder()
                    .id(2L)
                    .email(".com")
                    .birthday(LocalDate.of(2000, 1, 1))
                    .userDto2(userDto2)
                    .build();
        }

        @Benchmark
        public void withGeneralQueryClassProcessor(Blackhole blackhole) {
            blackhole.consume(QueryWrappers.parse(dto));
        }

    }

    public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(JmhTests.class.getSimpleName())
                .build();
        new Runner(options).run();
    }

    @Data
    @Builder
    @AllArgsConstructor
    @NoArgsConstructor
    static class UserDTO {

        @Query
        private Long id;

        @Query(value = ConditionType.LikeLeft.class)
        private String email;

        @Query(value = ConditionType.Ge.class)
        private LocalDate birthday;

        @NestedQuery
        private UserDTO2 userDto2;

    }

    @Data
    static class UserDTO2 {

        @Query(value = ConditionType.Like.class)
        private String name;

        @Query(value = ConditionType.Le.class)
        private Integer age;

    }


}